/*	Author		: Arga, Fan
 *	Created On	: Apr 28, 2011
 *	Description	: 
 */

package team8.paacdroid.activity;

import java.io.IOException;
import java.net.MalformedURLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import team8.paacdroid.R;
import team8.paacdroid.bean.Schedule;

import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.LinearLayout;
import android.widget.RadioGroup;
import android.widget.TextView;

public class ScheduleFinderActivity extends RootActivity implements TextWatcher {
	private HashMap<String, String> mapBusRoutesAndNames;
	
	// UI elements declarations
	Button btnSearchSchedule;
	TextView tvResult;
	AutoCompleteTextView actvRouteNoOrName;
	LinearLayout llAdvancedOptions;
	CheckBox cbAdvancedOptions;
	RadioGroup rgDirection;

	// Program parameters
	final String BASE_URL = "http://www.portauthority.org/atisdnn/";
	final String WEB_ENDPOINT = "default.aspx";
	final boolean OFFLINE_MODE = true;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		// Load the layout
		setContentView(R.layout.schedule_finder_activity);
		btnSearchSchedule = (Button) this.findViewById(R.id.btnSearchSchedule);
		actvRouteNoOrName = (AutoCompleteTextView) this.findViewById(R.id.actvRouteNoOrName);
		actvRouteNoOrName.addTextChangedListener(this);
		llAdvancedOptions = (LinearLayout) this.findViewById(R.id.llAdvancedOptions);
		cbAdvancedOptions = (CheckBox) this.findViewById(R.id.cbAdvancedOptions);
		rgDirection = (RadioGroup) this.findViewById(R.id.rgDirection);

		// Load the bus routes & names; attach it to the autocompletetextview
		mapBusRoutesAndNames = getBusRoutesAndNames();
		String[] arrStrings = mapBusRoutesAndNames.keySet().toArray(new String[0]);
		actvRouteNoOrName.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, arrStrings));
	}
	
	public void doScheduleFinder(View button) throws IOException {
		// TODO Get a fresh VIEWSTATE
		String viewState = getResources().getText(R.string.view_state_schedule_finder).toString();
		
		// Get the results
		HashMap<String, Object> result = processHttpResponse(createAndSendScheduleFinderHttpRequest(viewState));
		
		// Handle the result
		handleResult(result);
	}

	public String createAndSendScheduleFinderHttpRequest(String viewState) throws MalformedURLException, IOException {
		String result;
		HashMap<String, String> queryString = new HashMap<String, String>();
		
		// Get the travel date
		String strDate = "";
		if (llAdvancedOptions.getVisibility() == View.VISIBLE) {
			// TODO If the advanced options panel is visible, get time and date from the widgets
			
		} else {
			// If the advanced options panel is invisible, get current time and date
			Date now = new Date();
			Calendar cal = Calendar.getInstance();
			SimpleDateFormat sdf = new SimpleDateFormat("M/d/yyyy");
			cal.setTime(now);
			strDate = sdf.format(now);
		}
		queryString.put("Calendar2_txtCalendar", strDate);
		
		// Get the direction
		if (rgDirection.getCheckedRadioButtonId() == R.id.radioInbound) {
			queryString.put("radDirection", "I");
		} else if (rgDirection.getCheckedRadioButtonId() == R.id.radioOutbound) {
			queryString.put("radDirection", "O");
		}
		
		// Get the bus route
		String strRouteNo = actvRouteNoOrName.getText().toString();
		queryString.put("ddRoutes", mapBusRoutesAndNames.get(strRouteNo) != null ? mapBusRoutesAndNames.get(strRouteNo) : "");

		// Add hidden fields to coax the results from the webform
		queryString.put("__VIEWSTATE", viewState);
		queryString.put("btnSubmitSchedule", "Get Schedule");

		// Send a HTTP GET/POST request
//		result = sendHttpGetRequest(BASE_URL + WEB_ENDPOINT, queryString);
		if (!OFFLINE_MODE) {
			result = sendHttpPostRequest(BASE_URL + WEB_ENDPOINT, queryString);
		} else {
			result = "";
		}
		
		// Return result
		return result;
	}

	public HashMap<String, Object> processHttpResponse(String response) {
		HashMap<String, Object> result = new HashMap<String, Object>();
		
		// Prepare regex patterns for result determination
		Pattern patRealResult = Pattern.compile("<td class=\"tableheader\" nowrap=\"nowrap\" valign=\"Top\" colspan=\"4\"><span id=\"lblHeader1\">Route \\((\\w+?)\\) ([\\w `~!@#\\$%\\^\\*\\(\\)-_\\+;:',\\./\\{\\}\\[\\]\\|\\\\]+?)</span><br>");
		Pattern patInvalidViewState = Pattern.compile("");
		Pattern patNoDirection = Pattern.compile("");
		Pattern patNoTravelDate = Pattern.compile("");
		Matcher matRealResult = patRealResult.matcher(response);
		Matcher matInvalidViewState = patInvalidViewState.matcher(response);
		Matcher matNoDirection = patNoDirection.matcher(response);
		Matcher matNoTravelDate = patNoTravelDate.matcher(response);
		
		// Determine the type of the result
		if (matRealResult.find()) {
			// If the result is a list of itineraries (intended result), first check if this is indeed the intended result
			if (!matRealResult.group(1).equals(mapBusRoutesAndNames.get(actvRouteNoOrName.getText().toString()))) {
				result.put("Type", "Error");
				result.put("Message", "Please select a route from the options provided.");
			} else {
				result.put("Type", "Schedule");
				result.put("Schedule", grabSchedule(response));
			}
//		} else if (matInvalidViewState.find()) {
//			// TODO If the result is an invalid view state error
//			
//		} else if (matNoDirection.find()) {
//			// TODO If the result is an error due failure to assert direction
//			
//		} else if (matNoTravelDate.find()) {
//			// TODO If the result is an error due failure to assert travel date
//			
		} else {
			// If the result is none of the above
//			result.put("Type", "Error");
//			result.put("Message", "Unknown response.");
			result.put("Type", "Schedule");
			result.put("Schedule", grabSchedule(response));
		}
		
		// Return response
		return result;
	}
	
	public HashMap<String, String> getBusRoutesAndNames() {
		HashMap<String, String> arrRoutes = new HashMap<String, String>();
		
		// Get the bus routes and form value
		// TODO Get this from default.aspx
		arrRoutes.put("1 - Freeport Road", "1");
		arrRoutes.put("11 - Fineview", "11");
		arrRoutes.put("12 - McKnight", "12");
		arrRoutes.put("13 - Bellevue", "13");
		arrRoutes.put("14 - Ohio Valley", "14");
		arrRoutes.put("15 - Charles", "15");
		arrRoutes.put("16 - Brighton", "16");
		arrRoutes.put("17 - Shadeland", "17");
		arrRoutes.put("18 - Manchester", "18");
		arrRoutes.put("19L - Emsworth Limited", "19L");
		arrRoutes.put("2 - Mount Royal", "2");
		arrRoutes.put("20 - Kennedy", "20");
		arrRoutes.put("21 - Coraopolis", "21");
		arrRoutes.put("22 - McCoy", "22");
		arrRoutes.put("24 - West Park", "24");
		arrRoutes.put("26 - Chartiers", "26");
		arrRoutes.put("27 - Fairywood", "27");
		arrRoutes.put("28X - Airport Flyer", "28X");
		arrRoutes.put("29 - Robinson", "29");
		arrRoutes.put("31 - Bridgeville", "31");
		arrRoutes.put("36 - Banksville", "36");
		arrRoutes.put("38C - Green Tree Express", "38C");
		arrRoutes.put("39 - Brookline", "39");
		arrRoutes.put("4 - Troy Hill", "4");
		arrRoutes.put("40 - Mount Washington", "40");
		arrRoutes.put("41 - Bower Hill", "41");
		arrRoutes.put("43 - Bailey", "43");
		arrRoutes.put("44 - Knoxville", "44");
		arrRoutes.put("48 - Arlington", "48");
		arrRoutes.put("51 - Carrick", "51");
		arrRoutes.put("51L - Carrick Limited", "51L");
		arrRoutes.put("52L - Homeville Limited", "52L");
		arrRoutes.put("53 - Homestead Park", "53");
		arrRoutes.put("53L - Homestead Park Limited", "53L");
		arrRoutes.put("54 - North Side-Oakland-South Side", "54");
		arrRoutes.put("56 - Lincoln Place", "56");
		arrRoutes.put("57 - Hazelwood", "57");
		arrRoutes.put("58 - Greenfield", "58");
		arrRoutes.put("59 - Mon Valley", "59");
		arrRoutes.put("6 - Spring Hill", "6");
		arrRoutes.put("60 - Walnut-Crawford Village", "60");
		arrRoutes.put("61A - Wilkinsburg via Forbes Av", "61A");
		arrRoutes.put("61B - Braddock-Swissvale", "61B");
		arrRoutes.put("61C - McKeesport-Homestead", "61C");
		arrRoutes.put("61D - Murray", "61D");
		arrRoutes.put("63 - Edgewood", "63");
		arrRoutes.put("64 - Lawrenceville-Waterfront", "64");
		arrRoutes.put("65 - Squirrel Hill", "65");
		arrRoutes.put("67 - Monroeville", "67");
		arrRoutes.put("68 - Braddock Hills", "68");
		arrRoutes.put("69 - Trafford", "69");
		arrRoutes.put("7 - Spring Garden", "7");
		arrRoutes.put("71 - Edgewood Town Center", "71");
		arrRoutes.put("71A - Negley", "71A");
		arrRoutes.put("71B - Highland Park", "71B");
		arrRoutes.put("71C - Point Breeze", "71C");
		arrRoutes.put("71D - Hamilton", "71D");
		arrRoutes.put("74 - Homewood-Squirrel Hill", "74");
		arrRoutes.put("75 - Ellsworth", "75");
		arrRoutes.put("77 - Penn Hills", "77");
		arrRoutes.put("78 - Oakmont", "78");
		arrRoutes.put("79 - East Hills", "79");
		arrRoutes.put("8 - Perrysville", "8");
		arrRoutes.put("81 - Oak Hill", "81");
		arrRoutes.put("82 - Lincoln", "82");
		arrRoutes.put("83 - Webster", "83");
		arrRoutes.put("86 - Liberty", "86");
		arrRoutes.put("87 - Friendship", "87");
		arrRoutes.put("88 - Penn", "88");
		arrRoutes.put("89 - Garfield Commons", "89");
		arrRoutes.put("91 - Butler Street", "91");
		arrRoutes.put("93 - Lawrenceville-Oakland", "93");
		arrRoutes.put("BLLB - Library via Overbrook", "BLLB");
		arrRoutes.put("BLSV - South Hills Village via Overbrook", "BLSV");
		arrRoutes.put("G2 - West Busway", "G2");
		arrRoutes.put("G3 - Moon Flyer", "G3");
		arrRoutes.put("G31 - Bridgeville Flyer", "G31");
		arrRoutes.put("O1 - Ross Flyer", "O1");
		arrRoutes.put("O12 - McKnight Flyer", "O12");
		arrRoutes.put("O5 - Thompson Run Flyer", "O5");
		arrRoutes.put("P1 - East Busway-All Stops", "P1");
		arrRoutes.put("P10 - Allegheny Valley Flyer", "P10");
		arrRoutes.put("P12 - Holiday Park Flyer", "P12");
		arrRoutes.put("P13 - Mount Royal Flyer", "P13");
		arrRoutes.put("P16 - Penn Hills Flyer", "P16");
		arrRoutes.put("P17 - Lincoln Park Flyer", "P17");
		arrRoutes.put("P2 - East Busway Short", "P2");
		arrRoutes.put("P3 - East Busway-Oakland", "P3");
		arrRoutes.put("P67 - Monroeville Flyer", "P67");
		arrRoutes.put("P68 - Braddock Hills Flyer", "P68");
		arrRoutes.put("P69 - Trafford Flyer", "P69");
		arrRoutes.put("P7 - McKeesport Flyer", "P7");
		arrRoutes.put("P71 - Swisshelm Park-Rankin Flyer", "P71");
		arrRoutes.put("P76 - Lincoln Highway Flyer", "P76");
		arrRoutes.put("P78 - Oakmont Flyer", "P78");
		arrRoutes.put("RED - Beechview", "RED");
		arrRoutes.put("Y1 - Large Flyer", "Y1");
		arrRoutes.put("Y45 - Baldwin Manor Flyer", "Y45");
		arrRoutes.put("Y46 - Elizabeth Flyer", "Y46");
		arrRoutes.put("Y47 - Curry Flyer", "Y47");
		arrRoutes.put("Y49 - Prospect Flyer", "Y49");
		
		// Return result
		return arrRoutes;
	}
	
	public Schedule grabSchedule(String htmlResponse) {
		Schedule schedule = new Schedule();
		
		// TODO Grab all results from response page
		// Grab the stop names
		// Pattern patStopNames = Pattern.compile("<tr class=\"gridFixedHeader\" nowrap=\"nowrap\" align=\"Center\" valign=\"Bottom\" bgcolor=\"WhiteSmoke\">(.+?)</tr>", Pattern.DOTALL);
		
		// Create a dummy schedule array
		schedule.setRouteNo("71A");
		schedule.setRouteName("NEGLEY DOWNTOWN VIA OAKLAND");
		schedule.setServiceType("Weekday Service");
		schedule.setDirection("Inbound");
		schedule.setLegend("FS = Far Side; NS = Near Side; BTW = Between\nColumns with 'NO STOP' in header are just points of reference. You cannot get on or off the bus at that location.");
		String[] stopNames = {"ST CLAIR ST & BUNKER HILL APTS", "NEGLEY AVE & PENN", "NEGLEY AVE & CENTRE", "CRAIG ST & 5TH", "5TH AVE OPP ATWOOD", "6TH AVE & 5TH FS", "5TH AVE & MCMASTERS - NO STOP"};
		schedule.setStopNames(new ArrayList<String>(Arrays.asList(stopNames)));
		String[] areaNames = {"East Liberty", "East Liberty", "East Liberty", "Oakland", "Oakland", "Uptown", "Downtown"};
		schedule.setAreaNames(new ArrayList<String>(Arrays.asList(areaNames)));
		String[] stop1Times = {"4:27 AM", "4:57 AM", "5:27 AM", "5:46 AM", "5:59 AM", "6:19 AM", "6:26 AM", "6:36 AM", "6:46 AM", "6:56 AM", "7:06 AM", "7:16 AM", "7:26 AM", "7:36 AM", "7:46 AM", "7:56 AM", "8:06 AM", "8:16 AM", "8:27 AM", "8:37 AM", "8:47 AM", "8:57 AM", "9:07 AM", "9:17 AM", "9:27 AM", "9:37 AM", "9:47 AM", "9:57 AM", "10:07 AM", "10:17 AM", "10:27 AM", "10:37 AM", "10:47 AM", "10:57 AM", "11:07 AM", "11:17 AM", "11:27 AM", "11:37 AM", "11:47 AM", "11:57 AM", "12:07 PM", "12:17 PM", "12:27 PM", "12:37 PM", "12:47 PM", "12:57 PM", "1:07 PM", "1:17 PM", "1:27 PM", "1:37 PM", "1:47 PM", "1:57 PM", "2:07 PM", "2:17 PM", "2:27 PM", "2:37 PM", "2:47 PM", "2:57 PM", "3:07 PM", "3:17 PM", "3:25 PM", "3:35 PM", "3:45 PM", "3:55 PM", "4:05 PM", "4:15 PM", "4:25 PM", "4:35 PM", "4:45 PM", "4:55 PM", "5:05 PM", "5:15 PM", "5:32 PM", "5:42 PM", "5:52 PM", "6:02 PM", "6:19 PM", "6:49 PM", "7:19 PM", "7:53 PM", "8:23 PM", "8:53 PM", "9:23 PM", "9:53 PM", "10:23 PM", "10:57 PM", "11:27 PM", "11:57 PM", "12:27 AM", "1:12 AM"};
		String[] stop2Times = {"4:32 AM", "5:02 AM", "5:32 AM", "5:52 AM", "6:05 AM", "6:25 AM", "6:34 AM", "6:44 AM", "6:54 AM", "7:04 AM", "7:14 AM", "7:24 AM", "7:34 AM", "7:44 AM", "7:54 AM", "8:04 AM", "8:14 AM", "8:24 AM", "8:35 AM", "8:45 AM", "8:55 AM", "9:05 AM", "9:15 AM", "9:25 AM", "9:35 AM", "9:45 AM", "9:55 AM", "10:05 AM", "10:15 AM", "10:25 AM", "10:35 AM", "10:45 AM", "10:55 AM", "11:05 AM", "11:15 AM", "11:25 AM", "11:35 AM", "11:45 AM", "11:55 AM", "12:05 PM", "12:15 PM", "12:25 PM", "12:35 PM", "12:45 PM", "12:55 PM", "1:05 PM", "1:15 PM", "1:25 PM", "1:35 PM", "1:45 PM", "1:55 PM", "2:05 PM", "2:15 PM", "2:25 PM", "2:35 PM", "2:45 PM", "2:55 PM", "3:05 PM", "3:15 PM", "3:25 PM", "3:32 PM", "3:42 PM", "3:52 PM", "4:02 PM", "4:12 PM", "4:22 PM", "4:32 PM", "4:42 PM", "4:52 PM", "5:02 PM", "5:12 PM", "5:22 PM", "5:39 PM", "5:49 PM", "5:59 PM", "6:09 PM", "6:26 PM", "6:56 PM", "7:26 PM", "7:59 PM", "8:29 PM", "8:59 PM", "9:29 PM", "9:59 PM", "10:29 PM", "11:02 PM", "11:32 PM", "12:02 AM", "12:32 AM", "1:17 AM"};
		String[] stop3Times = {"4:34 AM", "5:04 AM", "5:34 AM", "5:55 AM", "6:08 AM", "6:28 AM", "6:38 AM", "6:48 AM", "6:58 AM", "7:08 AM", "7:18 AM", "7:28 AM", "7:38 AM", "7:48 AM", "7:58 AM", "8:08 AM", "8:18 AM", "8:28 AM", "8:39 AM", "8:49 AM", "8:59 AM", "9:09 AM", "9:19 AM", "9:29 AM", "9:39 AM", "9:49 AM", "9:59 AM", "10:09 AM", "10:19 AM", "10:29 AM", "10:39 AM", "10:49 AM", "10:59 AM", "11:09 AM", "11:19 AM", "11:29 AM", "11:39 AM", "11:49 AM", "11:59 AM", "12:09 PM", "12:19 PM", "12:29 PM", "12:39 PM", "12:49 PM", "12:59 PM", "1:09 PM", "1:19 PM", "1:29 PM", "1:39 PM", "1:49 PM", "1:59 PM", "2:09 PM", "2:19 PM", "2:29 PM", "2:39 PM", "2:49 PM", "2:59 PM", "3:09 PM", "3:19 PM", "3:29 PM", "3:35 PM", "3:45 PM", "3:55 PM", "4:05 PM", "4:15 PM", "4:25 PM", "4:35 PM", "4:45 PM", "4:55 PM", "5:05 PM", "5:15 PM", "5:25 PM", "5:42 PM", "5:52 PM", "6:02 PM", "6:12 PM", "6:29 PM", "6:59 PM", "7:29 PM", "8:02 PM", "8:32 PM", "9:02 PM", "9:32 PM", "10:02 PM", "10:32 PM", "11:04 PM", "11:34 PM", "12:04 AM", "12:34 AM", "1:19 AM"};
		HashMap <String, ArrayList<String>> timeList = new HashMap <String, ArrayList<String>>();
		timeList.put("ST CLAIR ST & BUNKER HILL APTS", new ArrayList<String>(Arrays.asList(stop1Times)));
		timeList.put("NEGLEY AVE & PENN", new ArrayList<String>(Arrays.asList(stop2Times)));
		timeList.put("NEGLEY AVE & CENTRE", new ArrayList<String>(Arrays.asList(stop3Times)));
		timeList.put("CRAIG ST & 5TH", new ArrayList<String>(Arrays.asList(stop1Times)));
		timeList.put("5TH AVE OPP ATWOOD", new ArrayList<String>(Arrays.asList(stop2Times)));
		timeList.put("6TH AVE & 5TH FS", new ArrayList<String>(Arrays.asList(stop3Times)));
		timeList.put("5TH AVE & MCMASTERS - NO STOP", new ArrayList<String>(Arrays.asList(stop1Times)));
		schedule.setStopSchedules(timeList);
		
		// Return result
		return schedule;
	}

	@Override
	public void afterTextChanged(Editable s) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void beforeTextChanged(CharSequence s, int start, int count,
			int after) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onTextChanged(CharSequence s, int start, int before, int count) {
		// TODO Auto-generated method stub
		
	}

	public void toggleAdvancedOptions(View checkBox) {
		if (llAdvancedOptions.getVisibility() == View.GONE) {
			// Make the advanced options box appear
			llAdvancedOptions.setVisibility(View.VISIBLE);
			
			// TODO Adjust the size of the form elements
			
		} else if (llAdvancedOptions.getVisibility() == View.VISIBLE) {
			// Make the advanced option box disappear
			llAdvancedOptions.setVisibility(View.GONE);
			
			// TODO Adjust the size of the form elements
		}
	}
	
	public void handleResult(HashMap<String, Object> result) {
		// Determine what to do with the result
		if (result.get("Type").equals("Schedule")) {
			
			// Create new intent
			Intent intentViewSchedule = new Intent(this, ViewScheduleActivity.class);
			
			// Create and attach the data bundle
			Bundle bundleSchedule = new Bundle();
			if (result.get("Schedule") != null && result.get("Schedule").getClass().equals(Schedule.class)) {
				bundleSchedule.putSerializable("Schedule", (Schedule) result.get("Schedule"));
				intentViewSchedule.putExtras(bundleSchedule);
			}
			
			// Directly call the activity
			startActivity(intentViewSchedule);
		} else if (result.get("Type").equals("Error")) {
			displayAlert(this, "Error", result.get("Message").toString(), "Close");
		}
	}
}
